﻿using System.Collections.Generic;
using UnityEngine;
using BridgeShips.Building;

namespace BridgeShips
{
	/// <summary>
	/// A collection of helpers, used by the PlayerBuilder to spawn previews, snap, place, etc.
	/// </summary>
    [System.Serializable]
    public class BuildingHelpers
    {
        public Building.BuildingPiece CurrentPreviewPiece { get { return m_CurrentPreviewPiece; } }

        public bool HasSocket { get { return m_HasSocket; } set { m_HasSocket = value; } }

        public bool PlacementAllowed { get { return m_PlacementAllowed; } }

        public Color PreviewColor { get { return m_PreviewColor; } set { m_PreviewColor = value; } }

        public float RotationOffset { get { return m_RotationOffset; } set { m_RotationOffset = value; } }

        [SerializeField]
        private LayerMask m_BuildingPieceMask ;

        [SerializeField]
        private LayerMask m_FreePlacementMask ;

        [SerializeField]
        private int m_BuildRange;

        [Header("Preview Pulsing Effect")]

        [SerializeField]
        private bool m_UsePulseEffect = true;

        [SerializeField]
        private bool m_PulseWhenSnapped = true;

        [SerializeField]
        private float m_PulseMin = 0.4f;


        private Building.BuildingPiece m_CurrentPreviewPiece;
        //private Building.BuildingPiece m_LastPlacedPiece;

        private GameObject m_CurrentPreview;
       // private Collider[] m_LastOverlappingPieces;

        private bool m_HasSocket;
        private bool m_PlacementAllowed = true;

        private Color m_PreviewColor;
        private float m_RotationOffset;

        private Transform m_Transform;


        //private PlayerEventHandler m_Player;
       // private AudioSource m_Audio;

		private Building.BuildingPiece m_CurrentPrefab;


        public void Initialize(Transform t, PlayerEventHandler pl, AudioSource aS)
        {
            m_Transform = t;
           // m_Player = pl;
            //m_Audio = aS;
        }

        public void ManagePreview()
        {
            ManageCollision();

            if(m_UsePulseEffect)
                ApplyPulse();

			//var renderers = m_CurrentPreviewPiece.Renderers;

			//for(int r = 0;r < renderers.Count;r ++)
			//{
			//	Material[] newMats = renderers[r].materials;
			//	for (int m = 0; m < newMats.Length; m++)
			//		newMats[m].color = m_PreviewColor;

			//	renderers[r].materials = newMats;
			//} 
        }

        private void ManageCollision()
        {
			UpdatePreviewColor();
        }

		private void UpdatePreviewColor()
        {
			Color c = m_PlacementAllowed ? new Color(0, 1, 0, m_PreviewColor.a) : new Color(1, 0, 0, m_PreviewColor.a);

            m_PreviewColor = c;
        }

        private void ApplyPulse()
        {
            if (!m_PulseWhenSnapped && m_HasSocket)
            {
                m_PreviewColor.a = 1;

                return;
            }

        }

        public void LookForSnaps()
        {
            m_CurrentPreview.gameObject.SetActive(GameController.LocalPlayer.CanShowObjectPreview.Get());

            Collider[] buildingPieces = Physics.OverlapSphere(m_Transform.position, m_BuildRange, m_BuildingPieceMask, QueryTriggerInteraction.Ignore);

            if(buildingPieces.Length > 0)
                HandleSnapPreview(buildingPieces);
            else if(!RaycastAndPlace())
                HandleFreePreview();
        }

        private void HandleFreePreview()
        {
            Transform toCurrentPos = (m_CurrentPreviewPiece.OutOfGroundHeight == 0) ? m_Transform : GameController.WorldCamera.transform;
            Vector3 currentPos = toCurrentPos.position + toCurrentPos.forward * m_BuildRange;

            if (m_CurrentPreviewPiece.OutOfGroundHeight == 0)
            {
                RaycastHit hit;
                Vector3 startPos = m_CurrentPreview.transform.position + new Vector3(0, 0.25f, 0);

                bool raycast = Physics.Raycast(startPos, Vector3.down, out hit, 1f, m_FreePlacementMask, QueryTriggerInteraction.Ignore);

                if (raycast)
                    currentPos.y = hit.point.y;
            }
            else
            {
                float minMove = m_CurrentPreviewPiece.AllowUnderTerrainMovement ? (m_Transform.position.y - m_CurrentPreviewPiece.OutOfGroundHeight) : 0;

                currentPos.y = Mathf.Clamp(currentPos.y, minMove, (m_Transform.position.y + m_CurrentPreviewPiece.OutOfGroundHeight));
            }

            m_CurrentPreview.transform.position = currentPos;
			m_CurrentPreview.transform.rotation = m_Transform.rotation * m_CurrentPrefab.transform.localRotation * Quaternion.Euler(m_CurrentPreviewPiece.RotationAxis * m_RotationOffset);


			m_HasSocket = false;
        }

        private void HandleSnapPreview(Collider[] buildingPieces)
        {
           // m_LastOverlappingPieces = buildingPieces;

            Camera cam = Camera.main;
            Ray ray = cam.ViewportPointToRay(Vector3.one * 0.5f);

            if(!RaycastAndPlace())
                HandleFreePreview();
        }

        private bool RaycastAndPlace()
        {
            Camera cam = Camera.main;
            Ray ray = cam.ViewportPointToRay(Vector3.one * 0.5f);

            RaycastHit hitInfo;

            if(Physics.Raycast(ray, out hitInfo, m_BuildRange, m_FreePlacementMask, QueryTriggerInteraction.Ignore))
            {
                //if(!m_CurrentPreviewPiece.RequiresSockets)
                //{
                    m_CurrentPreview.transform.position = hitInfo.point;
					m_CurrentPreview.transform.rotation = m_Transform.rotation * m_CurrentPrefab.transform.localRotation * Quaternion.Euler(m_CurrentPreviewPiece.RotationAxis * m_RotationOffset);

                    return true;
                //}
            }

            return false;
        }



        public void SpawnPreview(GameObject prefab)
        {
            if(CurrentPreviewPiece != null)
            CurrentPreviewPiece.SetTrigger( prefab.name);
        }

        public void PlacePiece()
        {
			if(m_CurrentPreview == null)
				return;

			GameObject placedPiece = GameObject.Instantiate(m_CurrentPrefab.gameObject, m_CurrentPreview.transform.position, m_CurrentPreview.transform.rotation);
            placedPiece.transform.SetParent(null);

            Building.BuildingPiece piece = placedPiece.GetComponent<Building.BuildingPiece>();

			
            m_RotationOffset = 0f;

            if (piece.PlacementFX)
                GameObject.Instantiate(piece.PlacementFX, piece.transform.position, piece.transform.rotation);


			m_HasSocket = false;
        }
        
        public void ClearPreview()
        {
            if (m_CurrentPreview != null)
            {
                GameObject.Destroy(m_CurrentPreview.gameObject);

                m_CurrentPreview = null;
                m_CurrentPreviewPiece = null;
            }
        }

        public bool PreviewExists()
        {
            if (m_CurrentPreview)
                return true;

            return false;
        }
    }
}